#include <stdio.h>
#include <stdlib.h>
//===============================================================================
// Original Author: CC Dharmani, Chennai (India) www.dharmanitech.com
// Target architecture: little-endian, 2-byte alignment, long = 32-bit, short = 16-bit
// Designed for maximum 2TB FAT32 formatted memory card
//===============================================================================

#include "fat32.h"
#include "global.h"
#include <string.h>

// Global variables for file read / write access
extern unsigned char   FileData[MAX_FILE_SIZE];
extern unsigned long   FileSize;

//===============================================================================
// Static variables to store FAT32 system information
extern unsigned char   buffer[MAX_SEC_PER_CLS*BYTE_PER_SECTOR];
extern unsigned long   firstDataSector, rootCluster, totalClusters;
extern unsigned short  sectorPerCluster, reservedSectorCount;
extern unsigned long   unusedSectors;
extern unsigned char   freeClusterCountUpdated;

//===============================================================================
// Function: calculate the first sector address of any given cluster.
// Inputs: clusterNumber - cluster number for which first sector is to be found.
// Outputs: none.
// Return: first sector address.
//===============================================================================
unsigned long getFirstSector (unsigned long clusterNumber)
{
	return (((clusterNumber - 2) * sectorPerCluster) + firstDataSector);
}

//===============================================================================
// Function: get cluster entry value from FAT to find out the next cluster in the chain
//           or set new cluster entry in FAT.
// Inputs: clusterNumber - current cluster number.
//         get_set - GET, if next cluster is to be found; or SET, if next cluster is to be set.
//         clusterEntry - next cluster number if get_set = SET; ignore otherwise.
// Outputs: none.
// Return: next cluster number if get_set = GET; else 0.
//===============================================================================
unsigned long getSetNextCluster (unsigned long clusterNumber, unsigned char get_set, unsigned long clusterEntry)
{
	unsigned short FATEntryOffset;
	unsigned long  *FATEntryValue;
	unsigned long  FATEntrySector;

	// get sector number of the cluster entry in the FAT
	FATEntrySector = unusedSectors + reservedSectorCount + (clusterNumber / CLSA_PER_SECTOR) ;

	// get the offset address in that sector number
	FATEntryOffset = (unsigned short) ( (clusterNumber % CLSA_PER_SECTOR) * 4 ) ;

	// read the sector into a buffer
	CardRead (FATEntrySector, 1, buffer);

	// get the cluster address from the buffer
	FATEntryValue = (unsigned long *) &buffer[FATEntryOffset];

	if (get_set == GET)
		return ((*FATEntryValue) & 0x0fffffff);

	*FATEntryValue = clusterEntry;	// for setting new value in cluster entry in FAT

	CardWrite (FATEntrySector, 1, buffer);

	return (0);
}

//===============================================================================
// Function: search for the next free cluster in the root directory starting from 
//           a specified cluster.
// Inputs:   next = 1 if search for next cluster, = 0 if search from input cluster.
//           startCluster - starting cluster.
// Outputs: none.
// Return: the next free cluster, or 0 if none.
//===============================================================================
unsigned long searchNextFreeCluster (unsigned char next, unsigned long startCluster)
{
	unsigned long cluster, *value, sector, currentCluster;
	unsigned char i;

	currentCluster = startCluster;
	startCluster -= (startCluster % CLSA_PER_SECTOR );	// to start with the first file in a FAT sector

	for (cluster = startCluster; cluster < totalClusters; cluster += CLSA_PER_SECTOR )
	{
		sector = unusedSectors + reservedSectorCount + ( cluster / CLSA_PER_SECTOR ) ;
		CardRead (sector, 1, buffer);
		for (i = 0; i < CLSA_PER_SECTOR; i++)
		{
			value = (unsigned long *) &buffer[i*4];
			if ( ((*value) & 0x0fffffff ) == 0 )		
			{													// found a free cluster, but
				if (! next || (cluster + i) != currentCluster )	// if caller asked for next, then don't return the same cluster
					return (cluster + i);
			}
		} 
	}
	
	return 0;
}

//===============================================================================
// Function: get or set next free cluster or total free clusters in FSinfo sector of SD card.
// Inputs: totOrNext - TOTAL_FREE or NEXT_FREE.
//         get_set - GET or SET.
//         FSEntry - new FS entry, when get_set = SET; ignore otherwise.
// Outputs: none.
// Return: - next free cluster, if totOrNext = NEXT_FREE & get_set = GET
//         - total number of free clusters, if totOrNext = TOTAL_FREE & get_set = GET
//         - 0xffffffff, if any error or if get_set = SET
//===============================================================================
unsigned long getSetClusterFSinfo (unsigned char totOrNext, unsigned char get_set, unsigned long FSEntry)
{
	struct FSInfo_Structure *FS;

	CardRead (unusedSectors+1, 1, buffer);

	FS = (struct FSInfo_Structure *) &buffer;

	if ((FS->leadSignature != 0x41615252) || (FS->structureSignature != 0x61417272) || (FS->trailSignature != 0xaa550000))
		return 0xffffffff;

	if (get_set == GET)
	{
		if (totOrNext == TOTAL_FREE)
			return (FS->freeClusterCount);

		else	// totOrNext = NEXT_FREE
			return (FS->nextFreeCluster);
	}
	else	// get_set = SET
	{
		if (totOrNext == TOTAL_FREE)
			FS->freeClusterCount = FSEntry;

		else	// totOrNext = NEXT_FREE
			FS->nextFreeCluster = FSEntry;

		CardWrite (unusedSectors+1, 1, buffer);    // update FSinfo
	}
 
	return 0xffffffff;
}

//===============================================================================
// Function: update the free memory count in the FSinfo sector. 
//           Whenever a file is deleted or created, this function will be called
//           to ADD or REMOVE clusters occupied by the file
// Inputs: flag - ADD or REMOVE.
//         size - file size in bytes.
// Outputs: none.
// Return: none.
//===============================================================================
void freeMemoryUpdate (unsigned char flag, unsigned long size)
{
	unsigned long freeClusters, totalClusterCount, cluster;
	unsigned long sector, *value;
	unsigned short i;

	if (! freeClusterCountUpdated)		// if free memory is not updated, re-count the free clusters
	{								
		freeClusters = 0;
		totalClusterCount = 0;
		cluster = rootCluster;    
		while (1)
		{
			sector = unusedSectors + reservedSectorCount + ( cluster / CLSA_PER_SECTOR ) ;
			CardRead (sector, 1, buffer);
			for (i = 0; i < CLSA_PER_SECTOR; i++)
			{
				value = (unsigned long *) &buffer[i*4];
				if ( ( (*value) & 0x0fffffff ) == 0 )
					freeClusters++;
				totalClusterCount++;
				if ( totalClusterCount == ( totalClusters + 2 ) ) break;
			}  
			if ( totalClusterCount == ( totalClusters + 2 ) ) break;
			cluster += CLSA_PER_SECTOR;
		} 
	}
	else							// otherwise, get it from the FSinfo sector
		freeClusters = getSetClusterFSinfo (TOTAL_FREE, GET, 0);

	// convert file size into number of clusters occupied
	if ((size % BYTE_PER_SECTOR) == 0) size =  size / BYTE_PER_SECTOR ;
	else                               size = (size / BYTE_PER_SECTOR) + 1 ;
	if ((size % (sectorPerCluster*4) ) == 0) size =  size / sectorPerCluster ;
	else                                     size = (size / sectorPerCluster ) + 1 ;

	if (flag == ADD)
		freeClusters = freeClusters + size;
	else	// flag = REMOVE
		freeClusters = freeClusters - size;

	getSetClusterFSinfo (TOTAL_FREE, SET, freeClusters);

	freeClusterCountUpdated = 1;
}

//===============================================================================
// Function: to read data from boot sector of SD card, to determine important
// parameters like bytesPerSector, sectorsPerCluster etc.
// Inputs: none.
// Outputs: (All global variables): 
//          firstDataSector, rootCluster, totalClusters, 
//          sectorPerCluster, reservedSectorCount, unusedSectors
// Return: true for normal completion; false for error.
//===============================================================================
bool getBootSectorData (void)
{
	struct BS_Structure *bpb;						// mapping the buffer onto the structure
	struct MBRinfo_Structure *mbr;
	struct partitionInfo_Structure *partition;
	unsigned long dataSectors;
	unsigned short bytesPerSector;

	unusedSectors = 0;

	CardRead (0, 1, buffer);

	bpb = (struct BS_Structure *)buffer;

	if (bpb->jumpBoot[0] != 0xE9 && bpb->jumpBoot[0] != 0xEB)	// check if it is boot sector
	{
		mbr = (struct MBRinfo_Structure *)buffer;			// if it is not boot sector, it must be MBR

		if (mbr->signature != 0xaa55) 
			return (false);						// if it is not even MBR then it's not FAT32

		partition = (struct partitionInfo_Structure *)(mbr->partitionData);		// first partition
		unusedSectors = partition->firstSector;									// the unused sectors, hidden to the FAT

		CardRead (partition->firstSector, 1, buffer);			// read the bpb sector
		bpb = (struct BS_Structure *) buffer;
		if (bpb->jumpBoot[0] != 0xE9 && bpb->jumpBoot[0] != 0xEB) 
			return (false); 
	}

	if (bpb->FATsize_F16 != 0)
		return (false);							// Not FAT32

	if ( bpb->fileSystemType[0] != 'F' ||
	     bpb->fileSystemType[1] != 'A' ||
	     bpb->fileSystemType[2] != 'T' ||
	     bpb->fileSystemType[3] != '3' ||
	     bpb->fileSystemType[4] != '2' )
		return (false);							// Not FAT32

	bytesPerSector      = ((bpb->bytesPerSectorH) << 8) + (bpb->bytesPerSectorL);
	sectorPerCluster    = bpb->sectorPerCluster;
	reservedSectorCount = bpb->reservedSectorCount;
	rootCluster         = bpb->rootCluster;							// + (sector / sectorPerCluster) + 1;
	firstDataSector     = bpb->hiddenSectors + reservedSectorCount + (bpb->numberofFATs * bpb->FATsize_F32);
	if (bytesPerSector != BYTE_PER_SECTOR)
		return (false);

	dataSectors   = bpb->totalSectors_F32 - bpb->reservedSectorCount - (bpb->numberofFATs * bpb->FATsize_F32);
	totalClusters = dataSectors / sectorPerCluster;

	if ( ( getSetClusterFSinfo (TOTAL_FREE, GET, 0) ) > totalClusters )	// check if FSinfo free clusters count is valid
		freeClusterCountUpdated = 0;									// just flag it instead of actually updating the
	else																// FSinfo structure because we don't want to update
		freeClusterCountUpdated = 1;									// unless it is a write or delete command

	return (true);
}

//===============================================================================
// Function: convert normal short file name into FAT format. 
// Inputs: fileName - pointer to the file name (13 char in size).
//         fileNameFAT - pointer to the converted file name (11 char in size).
// Outputs: none.
// Return: 0 - if no error; 1 - if error.
//===============================================================================
unsigned char convertFileName (unsigned char *fileName, unsigned char *fileNameFAT)
{
	unsigned char j, k;

	for (j=0; j<12; j++)
		if (fileName[j] == '.') break;

	if (j > 8) 
		return 1;			// invalid file name

	for (k=0; k<j; k++)		// setting file name
		fileNameFAT[k] = fileName[k];

	for (k=j; k<=7; k++)	// filling file name trail with blanks
		fileNameFAT[k] = ' ';

	j++;

	for (k=8; k<11; k++)	// setting file extention
	{
		if (fileName[j] != 0)
			fileNameFAT[k] = fileName[j++];
		else				// filling extension trail with blanks
			while (k < 11)
				fileNameFAT[k++] = ' ';
	}

	for (j=0; j<11; j++)	// converting small letters to caps
		if((fileNameFAT[j] >= 0x61) && (fileNameFAT[j] <= 0x7a))
			fileNameFAT[j] -= 0x20;

	return (0);
}

bool findFiles (unsigned char flag, unsigned char *fileNameFAT, dir_Structure *dirUpdate)
{
	unsigned long cluster, firstSector, nextCluster;
	struct dir_Structure *dir;
	unsigned short i, j, sector;

	cluster = rootCluster;		// root cluster

	while (1)
	{
		firstSector = getFirstSector (cluster);

		for (sector = 0; sector < sectorPerCluster; sector++)
		{
			CardRead (firstSector + sector, 1, buffer);		

			for (i = 0; i < BYTE_PER_SECTOR; i += 32)	// go thru each directory structure
			{
				dir = (struct dir_Structure*) &buffer[i];

				if ( ( flag == ADD_FILE) && ( (dir->name[0]==EMPTY) || (dir->name[0]==DELETED) ) )	// look for an empty slot to enter file info
				{
					*dir = *dirUpdate;								// update the file info structure
					CardWrite (firstSector + sector, 1, buffer);	// save file
					return (true);
				}

				// flag = SET_FILE, GET_FILE, DEL_FILE
				else if (dir->name[0] == EMPTY)			// indicates end of the file list of the directory
					return (false);						// file does not exist.

				else if ( (dir->name[0] != DELETED) && 
					      (dir->attrib != ATTR_LONG_NAME) &&
					      (dir->attrib != ATTR_VOLUME_ID) &&
					      (dir->attrib != ATTR_DIRECTORY) )
				{
					for (j=0; j<11; j++)
						if (dir->name[j] != fileNameFAT[j]) break;
					if (j == 11)				// file name match
					{
						if (flag == GET_FILE)
						{
							*dirUpdate = *dir;	// get the file info structure
							return (true);		// found the file and return
						}

						if (flag == SET_FILE)
						{
							*dir = *dirUpdate;	// set the file info structure
							CardWrite (firstSector + sector, 1, buffer);	
							return (true);		// found the file and return
						}

						else // flag = DEL_FILE
						{
							// mark file as 'deleted' in FAT table
							dir->name[0] = DELETED;   
							CardWrite (firstSector + sector, 1, buffer);
							*dirUpdate = *dir;	// get the file info structure
							return (true);
						}
					}
				}
			}
		}

		nextCluster = getSetNextCluster (cluster, GET, 0);

		if (nextCluster > 0x0ffffff6)
		{
			if (flag == ADD_FILE) 
			{
				if (nextCluster == 0x0fffffff)	// this situation will come when total files in root is multiple of (32*sectorPerCluster)
				{  
					nextCluster = searchNextFreeCluster (1, cluster);	// find next cluster for root directory entries
					getSetNextCluster (cluster, SET, nextCluster);		// link the new cluster of root to the previous cluster
					getSetNextCluster (nextCluster, SET, 0x0fffffff);	// set the new cluster as end of the root directory
					for (j = 0; j < sectorPerCluster * BYTE_PER_SECTOR; j++)
						buffer[j] = 0;									// clear new directory entry table
					CardWrite ( getFirstSector(nextCluster), sectorPerCluster, buffer );
				} 
				else
					return (false);		// End of Cluster Chain
			}
			else
				return (false);			// End of Cluster Chain
		}
	
		if (nextCluster == 0) 
			return (false);			// Error in getting cluster
   
		cluster = nextCluster;
	}
 
	return (false);
}


//===============================================================================
// Function: to get single file directory entry, update file directory entry,
//           add new directory entry, or to delete a specified file. 
// Inputs: flag - GET_FILE, SET_FILE, ADD_FILE, or DEL_FILE.
//         fileNameFAT - pointer to file name.
//         dirUpdate - directory entry values to be updated
// Outputs: dirUpdate - the updated directory entries.
// Return: true for normal completeion, false if eorror.
//===============================================================================
bool listfiles ()
{
	unsigned long cluster, firstSector, nextCluster;
	struct dir_Structure *dir;
	unsigned short i, sector;

	cluster = rootCluster;		// root cluster

	while (1)
	{
		firstSector = getFirstSector (cluster);

		for (sector = 0; sector < sectorPerCluster; sector++)
		{
			CardRead (firstSector + sector, 1, buffer);		

			for (i = 0; i < BYTE_PER_SECTOR; i += 32)	// go thru each directory structure
			{
				if (buffer[i] == 0x00)
				{
					//printf("Reached end of directory\n");
					return true;
				}

				else if (buffer[i] != 0xE5)
				{
					dir = (struct dir_Structure*) &buffer[i];
					
					// If we are at file entry
					if ( ( dir->attrib & 0x1E) == 0 )
					{
						int k;
						
						for(k = 0; k < 8; k++)
							printf("%c", dir->name[k]);
						
						printf(".");

						for (k=8; k<11;k++)
							printf("%c",dir->name[k]);

						printf(".......Size: %lu\n",dir->fileSize);
					}
				}
			}
		}

		nextCluster = getSetNextCluster (cluster, GET, 0);

		if (nextCluster > 0x0ffffff6)
		{
			return (false);			// End of Cluster Chain
		}
	
		if (nextCluster == 0) 
			return (false);			// Error in getting cluster
   
		cluster = nextCluster;
	}
 
	return (false);
}

//===============================================================================
// Function: verify a specified file if flag exists.
// Inputs: fileName - pointer to file name.
// Outputs: none.
// Return: true if file exist, false otherwise.
//===============================================================================
bool FAT32Verify (unsigned char *fileName)
{
	unsigned char fileNameFAT[11];
	struct dir_Structure dirBuffer;

	if ( convertFileName (fileName, fileNameFAT) )	// convert fileName into FAT format
		return (false);

	return ( findFiles (GET_FILE, fileNameFAT, &dirBuffer) );
}

//===============================================================================
// Function: read a specified file.
// Inputs: fileName - pointer to file name.
// Outputs: none.
// Return: true for normal completion; false for error.
//===============================================================================
bool FAT32Read (unsigned char *fileName)
{
	unsigned char fileNameFAT[11];
	struct dir_Structure dirBuffer, *dir;
	unsigned long k, cluster, byteCounter = 0, firstSector;

	if ( convertFileName (fileName, fileNameFAT) )	// convert fileName into FAT format
		return (false);
	dir = &dirBuffer;
	if ( ! findFiles (GET_FILE, fileNameFAT, dir) )	// get the file location
		return (false);								// file not exist

	cluster = (((unsigned long) dir->firstClusterHI) << 16) | dir->firstClusterLO;

	FileSize = dir->fileSize;

	for (k = 0; k < MAX_FILE_SIZE/BYTE_PER_SECTOR; k += sectorPerCluster)	// read clusters
	{
		if (k * BYTE_PER_SECTOR >= FileSize) 
			return (true);		// done reading
		firstSector = getFirstSector (cluster);
		CardRead ( firstSector, sectorPerCluster, FileData + k * BYTE_PER_SECTOR );
		cluster = getSetNextCluster (cluster, GET, 0);
		if (cluster == 0) return (false);		// Error in getting cluster
	}

	return (false);				// pass the max boundary
}

//===============================================================================
// Function: to create a file in FAT32 format in the root directory, or to
//           append data to the file for the same file name.
// Inputs: fileName - pointer to file name.
// Outputs: none.
// Return: true for normal completion; false for error.
//===============================================================================
bool FAT32Write (unsigned char *fileName)
{
	unsigned char fileNameFAT[11];
	struct dir_Structure dirBuffer, *dir;
	unsigned char appendFile=0, done=0;
	unsigned long i, j, firstCluster, cluster, prevCluster, nextCluster, freeClusters, startBlock, fileOffset;

	if ( convertFileName (fileName, fileNameFAT) )	// convert fileName into FAT format
		return (false);
	dir = &dirBuffer;
	appendFile = findFiles (GET_FILE, fileNameFAT, dir);	// get the file location

	//---------- Check if there is available space ----------
	freeClusters = getSetClusterFSinfo (TOTAL_FREE, GET, 0);
	if ( FileSize > freeClusters * sectorPerCluster * BYTE_PER_SECTOR )
		return (false);					// Not enough disk space

	//---------- Append file processing ----------
	if (appendFile)	
	{
		//---------- Append file search for the last cluster ----------
		cluster = (((unsigned long) dir->firstClusterHI) << 16) | dir->firstClusterLO;
		fileOffset = dir->fileSize;				// assume initial file size is valid
		while (1)		
		{
			nextCluster = getSetNextCluster (cluster, GET, 0);
			if (nextCluster == 0x0fffffff) break;
			cluster = nextCluster;
			fileOffset -= sectorPerCluster * BYTE_PER_SECTOR;	// and will never go below zero
		}

		//---------- Append file write until the end of the remaining cluster ----------
		startBlock = getFirstSector (cluster);
		j = 0;	// use j as a byte counter
		CardRead (startBlock, sectorPerCluster, buffer);
		for (i = fileOffset; i < (unsigned long)sectorPerCluster * BYTE_PER_SECTOR && !done; i++)
		{
			buffer[i] = FileData[j++];	
			if (j >= FileSize) done = 1 ;
		}
		CardWrite (startBlock, sectorPerCluster, buffer);

		//---------- Append file continue to write using new cluster until finish ----------
		if (! done)
		{
			firstCluster = cluster;
			cluster = getSetClusterFSinfo (NEXT_FREE, GET, 0);
			if (cluster > totalClusters || ! freeClusterCountUpdated)	// if it is just formatted card
			{
				freeMemoryUpdate (ADD, 0);		// update the total free memory in FSinfo sector
				cluster = rootCluster;
			}
			cluster = searchNextFreeCluster (0, cluster);	// this make certain that it is really free
			if (cluster == 0) return (false);				// no free cluster
			getSetNextCluster (firstCluster, SET, cluster);	// link to next cluster

			while (1)
			{
				prevCluster = cluster;
				startBlock = getFirstSector (cluster);
				CardWrite (startBlock, sectorPerCluster, FileData + j);
				j += sectorPerCluster * BYTE_PER_SECTOR;
				if (j >= FileSize)							// finished writing
					break;
				cluster = searchNextFreeCluster (1, prevCluster);	// look for a free cluster
				if (cluster == 0)							// no free cluster
				{
					cluster = firstCluster;
					while (cluster != prevCluster) // go back and mark all the clusters as 'free'
					{
						nextCluster = getSetNextCluster (cluster, GET, 0);
						getSetNextCluster (cluster, SET, 0);
						cluster = nextCluster;
					}
					getSetNextCluster (firstCluster, SET, 0x0fffffff);		
					return (false);
				}
				getSetNextCluster (prevCluster, SET, cluster);	// link to next cluster
			}
		}

		getSetNextCluster (cluster, SET, 0x0fffffff);		// last cluster of the file, marked EOF
		cluster = searchNextFreeCluster (1, prevCluster);	// search for a free cluster to be used for next free
		getSetClusterFSinfo (NEXT_FREE, SET, cluster);		// update FSinfo next free cluster entry

		//---------- Append file update directory structure ----------
		dir->createTime = FILE_HOUR<<11 | FILE_MINUTE<<5 | FILE_SECOND;
		dir->createDate = (FILE_YEAR-1980)<<9 | FILE_MONTH<<5 | FILE_DAY;
		dir->lastAccessDate = (FILE_YEAR-1980)<<9 | FILE_MONTH<<5 | FILE_DAY;
		dir->writeTime = FILE_HOUR<<11 | FILE_MINUTE<<5 | FILE_SECOND;
		dir->writeDate = (FILE_YEAR-1980)<<9 | FILE_MONTH<<5 | FILE_DAY;
		dir->fileSize += FileSize;

		if ( ! findFiles (SET_FILE, fileNameFAT, dir) )
			return (false);

		freeMemoryUpdate (REMOVE, FileSize);	// updating free memory count in FSinfo sector;

		return (true);
	}

	//---------- Create file processing ----------
	cluster = getSetClusterFSinfo (NEXT_FREE, GET, 0);
	if (cluster > totalClusters || ! freeClusterCountUpdated)	// if it is just formatted card
	{
		freeMemoryUpdate (ADD, 0);		// update the total free memory in FSinfo sector
		cluster = rootCluster;
	}
	cluster = searchNextFreeCluster (0, cluster);	// this make certain that it is really free
	if (cluster == 0) return (false);					// no free cluster
	firstCluster = cluster;

	j = 0;	// use j as a byte counter
	while (1)				// write the file cluster by cluster
	{
		prevCluster = cluster;
		startBlock = getFirstSector (cluster);
		CardWrite (startBlock, sectorPerCluster, FileData + j);	// write one cluster
		j += sectorPerCluster * BYTE_PER_SECTOR;
		if (j >= FileSize)									// finished writing
			break;
		cluster = searchNextFreeCluster (1, prevCluster);	// look for a free cluster
		if (cluster == 0)									// no free cluster
		{
			cluster = firstCluster;
			while (cluster != prevCluster) // go back and mark all the clusters as 'free'
			{
				nextCluster = getSetNextCluster (cluster, GET, 0);
				getSetNextCluster (cluster, SET, 0);
				cluster = nextCluster;
			}
			return (false);
		}
		getSetNextCluster (prevCluster, SET, cluster);		// link to next cluster
	}

	getSetNextCluster (cluster, SET, 0x0fffffff);		// last cluster of the file, marked EOF
	cluster = searchNextFreeCluster (1, prevCluster);	// search for a free cluster to be used for next free
	getSetClusterFSinfo (NEXT_FREE, SET, cluster);		// update FSinfo next free cluster entry

	//---------- Create file update directory structure ----------
	dir = &dirBuffer;
	for (j=0; j<11; j++)
		dir->name[j] = fileNameFAT[j];
	dir->attrib = ATTR_ARCHIVE;		// settting file attribute as 'archive'
	dir->NTreserved = 0;			// always set to 0
	dir->timeTenth = 0;				// always set to 0
	dir->createTime = FILE_HOUR<<11 | FILE_MINUTE<<5 | FILE_SECOND;
	dir->createDate = (FILE_YEAR-1980)<<9 | FILE_MONTH<<5 | FILE_DAY;
	dir->lastAccessDate = (FILE_YEAR-1980)<<9 | FILE_MONTH<<5 | FILE_DAY;
	dir->writeTime = FILE_HOUR<<11 | FILE_MINUTE<<5 | FILE_SECOND;
	dir->writeDate = (FILE_YEAR-1980)<<9 | FILE_MONTH<<5 | FILE_DAY;
	dir->firstClusterHI = (unsigned short) ((firstCluster & 0xffff0000) >> 16 );;
	dir->firstClusterLO = (unsigned short)  (firstCluster & 0x0000ffff);
	dir->fileSize = FileSize;

	if ( ! findFiles (ADD_FILE, fileNameFAT, dir) )
		return (false);

	freeMemoryUpdate (REMOVE, FileSize);	// updating free memory count in FSinfo sector

	return (true);
}

//===============================================================================
// Function: to delete a specified file from the root directory.
// Inputs: fileName - pointer to file name.
// Outputs: none.
// Return: true for normal completion; false for error.
//===============================================================================
bool FAT32Delete (unsigned char *fileName)
{
	dir_Structure dirBuffer, *dir;
	unsigned char fileNameFAT[11];
	unsigned long firstCluster, cluster;

	if ( convertFileName (fileName, fileNameFAT) )
		return (false);

	dir = &dirBuffer;
	if ( ! findFiles (DEL_FILE, fileNameFAT, dir) )
		return (false);

	firstCluster = (((unsigned long) dir->firstClusterHI) << 16) | dir->firstClusterLO;

	// update total free cluster entry in FSinfo sector
	freeMemoryUpdate (ADD, dir->fileSize);
	// update next free cluster entry in FSinfo sector
	cluster = getSetClusterFSinfo (NEXT_FREE, GET, 0);
	if (firstCluster < cluster)
		getSetClusterFSinfo (NEXT_FREE, SET, firstCluster);

	// mark all the clusters allocated to the file as 'free'
	while (1) 
	{
		cluster = getSetNextCluster (firstCluster, GET, 0);
		getSetNextCluster (firstCluster, SET, 0);
		if (cluster > 0x0ffffff6) 
			return (true);			// file deleted and exit
		firstCluster = cluster;
	}

	return (false);
}

//===============================================================================
// Function: to initialize the FAT32 system.
// Inputs: none.
// Outputs: none.
// Return: true for normal completion; false for error.
//===============================================================================
bool FAT32Init (void)
{
	unsigned short bytesize;
	
	// Check structure size to make sure alignment is correct.
	// This part can be eliminated once CPU architecture is fixed.
	bytesize = sizeof (MBRinfo_Structure);
	if (bytesize != 512) return (false);
	bytesize = sizeof (partitionInfo_Structure);
	if (bytesize != 16) return (false);
	bytesize = sizeof (BS_Structure);
	if (bytesize != 512) return (false);
	bytesize = sizeof (FSInfo_Structure);
	if (bytesize != 512) return (false);
	bytesize = sizeof (dir_Structure);
	if (bytesize != 32) return (false);

	// Initialize boot sector data
	if (! getBootSectorData () ) return (false);

	return (true);
}
